using BS.Domain;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using System.Security.Claims;

namespace EFAuditTrail.Interceptor;

public class AuditTrailInterceptor : SaveChangesInterceptor
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public AuditTrailInterceptor(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public override InterceptionResult<int> SavingChanges(DbContextEventData data, InterceptionResult<int> result)
    {
        TrackChanges(data);
        return base.SavingChanges(data, result);
    }

    public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData data, InterceptionResult<int> result, CancellationToken cancellationToken = default)
    {
        TrackChanges(data);
        return base.SavingChangesAsync(data, result, cancellationToken);
    }

    private void TrackChanges(DbContextEventData data)
    {
        ArgumentNullException.ThrowIfNull(data.Context);
        data.Context.ChangeTracker.DetectChanges();

        foreach (var entry in data.Context.ChangeTracker.Entries())
        {
            //遍历所有要操作的实体
            if (entry.Entity is IAudit auditable)
            {
                switch (entry.State)
                {
                    case EntityState.Deleted:
                        UpdateAuditFields(auditable, "Remove");
                        entry.State = EntityState.Modified;
                        break;

                    case EntityState.Added:
                        UpdateAuditFields(auditable, "Create");
                        break;

                    case EntityState.Modified:
                        UpdateAuditFields(auditable, "Update");
                        break;
                }
            }
        }
    }

    private void UpdateAuditFields(IAudit auditable, string action)
    {
        var currentTime = DateTime.UtcNow;
        //const int adminId = 888;
        //const string adminName = "Admin";
         int adminId = Convert.ToInt32(_httpContextAccessor.HttpContext?.User.FindFirstValue("Jti"));
        string? adminName = _httpContextAccessor.HttpContext?.User.FindFirstValue("Sub");

        switch (action)
        {
            case "Remove":
                
                auditable.CreateName = adminName;
                auditable.AuditDate = currentTime;
                break;

            case "Create":
                auditable.CreateName = adminName;
                auditable.AuditDate = currentTime;
                break;

            case "Update":
                auditable.UpdateName = adminName;
                auditable.UpdateTime = currentTime;
                break;
        }
    }
}
